<?php

namespace App\Common\Utill;

use Elasticsearch\ClientBuilder;
use Illuminate\Support\Facades\Log;

class Elastic
{
    private $client;  // 链接
    private $index;   // 索引
    private $settings;   // 索引配置
    private $type = '_doc';       // 类型
    private $mappings;   // 索引定制化类型
    private $where;   // where条件
    private $data;   // data数据
    private $order;     // 排序
    private $size;      // 每页内容数


    public function __construct()
    {
        //构建客户端对象
        $hostType = env("ES_HOST_TYPE","online");
        $host = config("ESConfig.".$hostType, [
            [
                'host'   => '127.0.0.1', //域名
                'port'   => '9200', // 端口
                'scheme' => 'http', // 协议
                'path'   => '', // path
                'user'   => 'elastic', // 账号
                'pass'   => 'hC0!gO5*bT', // 密码
            ]
        ]);
        // 过滤未启用服务
        foreach ($host as $key => $value) {
            if (isset($value['isOpen']) && empty($value['isOpen'])) {
                unset($host[$key]);
            }
        }

        $this->client = ClientBuilder::create()
                                     ->setHosts($host)
                                     ->build();

        //$this->client = ClientBuilder::create()->setHosts(['127.0.0.1:9200'])->build();
    }


    /**
     * 指定索引名称
     * @param $iname  索引名称 多索引以逗号分隔：eg:video,user
     * @return $this
     */
    public function index($iname = '')
    {
        $this->index = $iname;
        return $this;
    }


    /**
     * 指定类型名称
     * @param $tname  类型名称
     * @return $this
     */
    public function type($tname = '')
    {
        $this->type = $tname;
        return $this;
    }


    /**
     * 索引设置
     * @param int $shards 数据分片数
     * @param int $replicas 副本分片数
     * @param string $fc 指定默认分词
     */
    public function settings($shards = 3, $replicas = 2)
    {
        $this->settings = array(
            'number_of_shards' => $shards,
            'number_of_replicas' => $replicas,
            'index' => array('analysis.analyzer.default.type' => 'ik_max_word')
        );
        return $this;
    }


    /**
     * 缓冲字段信息  array('字段名'=> 字段值,....)
     * @param array $data
     * @return $this
     */
    public function data($data = array())
    {
        $this->data = $data;
        return $this;
    }


    /**
     * 排序字段
     * @param $ord
     * @return $this
     */
    public function order($ord)
    {
        if (is_array($ord)) {
            $this->order = $ord;
        } else {
            $this->order = '';
        }
        return $this;
    }


    /**
     * 设置分页内容条数
     * @param int $size 每页显示数量
     * @return $this
     */
    public function pagesize($size = 10)
    {
        if (is_int($size) && $size > 0) {
            $this->size = $size;
        } else {
            $this->size = 10;
        }
        return $this;
    }


    /**
     * 定义搜索条件
     * @param array $q
     * @return $this
     * eg: $q array('match',['testField' => 'abc'])
     *        array('bool',['testField' => 'abc'])
     *        bool:  [
     * 'filter' => [
     * 'term' => [ 'my_field' => 'abc' ]
     * ],
     * 'should' => [
     * 'match' => [ 'my_other_field' => 'xyz' ]
     * ]
     *              ]
     *              [
     * 'must' => [
     * [ 'match' => [ 'testField' => 'abc' ] ],
     * [ 'match' => [ 'testField2' => 'xyz' ] ],
     * ]
     */
    public function where($q = [])
    {
        $where = array();
        if (count($q) > 0 && is_array($q)) {
            switch ($q[0]) {
                case 'match':
                    $where['match'] = $q[1];
                    break;

                case 'multi_match':
                case 'query_string':
                    $where[$q[0]] = $q[1];
                    break;

                case 'wildcard':
                    $where['wildcard'] = $q[1];
                    break;

                case 'bool':
                    $where['bool'] = $q[1];
                    break;

                default:
                    echo 'Search criteria matching failed!';
                    break;
            }
//             $this->where = !empty($this->where) ? array_merge($this->where,$where) : $where;
            $this->where = $where;
        }
        return $this;
    }


    /**
     * 选择返回字段
     * @param array $field
     */
    public function fields($field = [])
    {
        if (is_array($field)) {

        }
    }


    /**
     * 索引字段类型设置
     * @param array $properties 字段类型
     * @param bool $_source
     * @return $this
     */
    public function mappings($properties, $_source = true)
    {
        if ($this->type) {
            $this->mappings = array(
                '_source' => array(
                    'enabled' => $_source
                ),
                'properties' => $properties
            );
        }
        return $this;
    }


    /**
     * 创建索引
     * @param array $body
     */
    public function create($body = [])
    {
        $params = array(
            'index' => $this->index,
        );
        if ($this->settings && is_array($this->settings)) $params['body']['settings'] = $this->settings;
        if ($this->mappings && is_array($this->mappings)) $params['body']['mappings'] = $this->mappings;
        $this->client->indices()->create($params);
    }


    /**
     * 删除索引
     * @param string $index 索引名
     * @return bool|mixed
     */
    public function delIndex($index = '')
    {
        if ($this->index || $index) {
            if ($this->index) {
                $rt = $this->client->indices()->delete(['index' => $this->index]);
            } else {
                $rt = $this->client->indices()->delete(['index' => $index]);
            }
            return isset($rt['acknowledged']) ? $rt['acknowledged'] : false;
        }
        return false;
    }


    /**
     * 添加单条文档
     * @param $body 添加字段内容
     * @param string $id 指定文档索引id
     */
    public function add($body, $id = '')
    {
        $params = [
            'index' => $this->index,
            'type' => $this->type,
            'body' => $body
        ];
        if ($id) $params['id'] = $id;
        $rt = $this->client->index($params);
    }


    /**
     * 批量添加文档
     */
    public function blukAdd()
    {
        return $this->client->bulk($this->data);
    }


    /**
     * 获取文档
     * @param string $id 文档索引id
     * @return array
     */
    public function find($id = '')
    {
        $params = [
            'index' => $this->index,
            'type' => $this->type,
            'id' => $id
        ];
        return $this->client->get($params);
    }


    /**
     * 获取多个文档
     * @param array $ids 文档id
     * @return array
     */
    public function getAll($ids)
    {
        $params = [
            'index' => $this->index,
            'type' => $this->type,
            'ids' => ['ids' => $ids]
        ];
        return $this->client->get($params);
    }


    /**
     * 更改现存字段，或添加新字段
     * @param string $id 主键索引id
     */
    public function save($id = '')
    {
        $params = [
            'index' => $this->index,
            'type' => $this->type,
            'id' => $id,
            'body' => [
                'doc' => $this->data
            ]
        ];
        $rt = $this->client->update($params);
    }

    /**
     * 指定ID批量更新
     * @param string $id
     * @return bool
     * @throws \Exception
     */
    public function bulkUpdateById($id=""){

        if (!$this->data) {
            throw new \Exception("更新数据不能为空！");
        }
        if ($this->where) {
            $fields = '';
            foreach ($this->data as $k=>$v){
                $fields .="ctx._source.{$k} = $v;";
            }
            $fields = trim($fields,';');
            // 通过查询更新
            $params = [
                'update' => $this->index,
                'type' => $this->type,
                'body' => [
                    'query' => $this->where,
                    'script'=>[
                        "inline"=> $fields,
                        'lang'=>'painless'
                    ]
                ]
            ];
            $this->client->updateByQuery($params);
            return true;
        }
        if(!$id) {
            throw new \Exception("id不能为空！");
        }
        if (is_array($id)) {
            $params['body'] = array();
            foreach($id as $val)
            {
                $params['body'][] = array(
                    'update' => array(
                        '_index' => $this->index,
                        '_type' => $this->type,
                        '_id' => $val
                    )
                );
                $params['body'][] =["doc"=>$this->data];
            }
            Log::info('修改服务地址同步es----------'.json_encode($params));
             $a = $this->client->bulk($params);
             Log::INFO('es返回结果---------'.json_encode($a));
            // 批量更新数据
            return true;
        }
        // 更新单条数据
        $params = [
            'index' => $this->index,
            'type' => $this->type,
            'id' => $id,
            'body' => ["doc"=>$this->data]
        ];
        $re = $this->client->update($params);
        if (isset($re['_shards']['failed']) && $re['_shards']['failed']==0) {
            return true;
        }
        return false;
    }


    /**
     * 删除文档
     * @param string $id 文档索引id
     * @return bool
     * @throws \Exception
     */
    public function delete($id = '')
    {
        if (!$this->index) {
            throw new \Exception("索引不能为空！");
        }
        $type = $this->type ? $this->type : '_doc';
        $re = $this->client->delete([
            'index' => $this->index,
            'type' => $type,
            'id' => $id
        ]);
        if (isset($re['_shards']['failed']) && $re['_shards']['failed'] == 0) {
            return true;
        }
        return false;
    }


    /**
     * 搜索查询结果
     * @return array
     */
    public function select($size = 3, $from = 0, $field = [])
    {
        $body = array(
            'query' => $this->where,
//             'sort' => [
//                 ['id'=> ['order'=>'desc']]
//             ],
            'highlight' => [
                'pre_tags' => ["<em>"],
                'post_tags' => ["</em>"],
                'fields' => [
                    "title" => new \stdClass()
                ]
            ],
            'from' => $from,  // 分页
            'size' => $size
        );
        return $this->client->search([
            'index' => $this->index,
            'type' => $this->type,
            'body' => $body
        ]);
    }

    public function search($body)
    {
        $data = $this->client->search([
            'index' => 'video',
            'type' => $this->type,
            'body' => $body
        ]);

        $video = [];
        foreach ($data['hits']['hits'] as &$val) {
            array_push($video, $val['_source']);
        }
        return array_keys(arrayChangeKey($video, 'id'));
    }


}
